//
//  SSEmoticonManager.swift
//  表情包数据
//
//  Created by 叶竞泽 on 2017/2/3.
//  Copyright © 2017年 JingZe. All rights reserved.
//

import Foundation
import YYModel

/// 表情管理器
class SSEmoticonManager {
    
    // 为了便于表情的复用,建立单例,只加载一次表情数据
    
    /// 表情管理器的单例
    static let shared = SSEmoticonManager()
    
    /// 表情包懒加载数组 - 第一个数组是最近表情,加载之后为空
    lazy var packages = [SSEmoticonPackage]()
    
    /// Bundle资源实例
    lazy var bundle: Bundle? = {
        
        guard let path: String = Bundle.main.path(forResource: "HMEmoticon.bundle", ofType: nil), let bundle = Bundle(path: path) else {
            return nil
        }
        
        return bundle
    }()
    
    /// 添加最近使用的表情
    ///
    /// - Parameter emoticon: 选中的表情
    func recentEmoticon(emoticon: SSEmoticon) {
        
        // 1.增加表情的使用次数
        emoticon.times += 1
        // 2.是否已经记录了该表情,如果没有记录就添加记录
        if packages.first?.emoticons.contains(emoticon) == false {
            
            packages.first?.emoticons.append(emoticon)
        }
        // 3.根据使用次数排序,使用次数高的排在前面
        packages.first?.emoticons.sort { $0.times > $1.times }
        // 4.判断表情数组长度是否超过20,如果超过,删除超出部分
        
        if packages[0].emoticons.count > 20 {
            packages.first?.emoticons.removeSubrange(20 ..< packages[0].emoticons.count)
        }
    }
    
    /// 构造函数,如果在init之前增加private修饰符,可以要求调用者必须通过shared访问对象
    private init() {
        loadPackage()
    }
    
}

// MARK: - 表情包数据处理
fileprivate extension SSEmoticonManager {
    
    // 1.读取Emoticons.plist
    // 按照Bundle默认的目录结构设定,就可以直接搜索读取Resources, Bundle - Contents - Resources
    /**
     [["bgImageName": "left", "groupName": "最近"], 
        ["bgImageName": "mid", "directory": "default", "groupName": "默认"],
        ["bgImageName": "mid", "directory": "emoji", "groupName": "emoji"],
        ["bgImageName": "right", "directory": "lxh", "groupName": "浪小花"]]
     */
    fileprivate func loadPackage() {
        
        guard let path: String = Bundle.main.path(forResource: "HMEmoticon.bundle", ofType: nil), let bundle = Bundle(path: path), let plistPath = bundle.path(forResource: "emoticons.plist", ofType: nil), let arr = NSArray(contentsOfFile: plistPath) as? [[String: String]], let models = NSArray.yy_modelArray(with: SSEmoticonPackage.self, json: arr) as? [SSEmoticonPackage] else {
            return
        }
        
        // 设置表情包数据
        packages += models
    }
    
}

// MARK: - 表情符号处理
extension SSEmoticonManager {
    
    /// 将给定的字符串转换成属性字符串
    ///
    /// - Parameter string: 给定的字符串
    /// - Returns: 转换后的属性字符串
    func emoticonString(string: String, font: UIFont) -> NSAttributedString {
        
        let attr = NSMutableAttributedString(string: string)
        
        // 1.建立正则表达式,过滤所有的表情
        // []()都是正则表达式中的保留字,如果要匹配,需要转义
        let patten = "\\[.*?\\]"
        guard let regx = try? NSRegularExpression(pattern: patten, options: []) else {
            return attr
        }
        let results = regx.matches(in: string, options: [], range: NSRange(location: 0, length: string.characters.count))
        
        // 2.遍历结果 - 倒序遍历,因为替换字符串后字符串的长度会改变,会出现超出边界的问题
        for match in results.reversed() {
            
            let range = match.rangeAt(0)
            let subString = (attr.string as NSString).substring(with: range) as String
            
            // 1).使用subString查找对应的表情符号
            guard let imageText = SSEmoticonManager.shared.findEmoticon(withString: subString)?.imageText(font: font) else {
                return attr
            }
            // 2).替换原有的属性文本
            attr.replaceCharacters(in: range, with: imageText)
        }
        
        // 3.统一设置字体属性
        attr.addAttributes([NSFontAttributeName: font, NSForegroundColorAttributeName: UIColor.darkGray], range: NSRange(location: 0, length: attr.length))
        
        return attr
        
    }
    
    /// 根据string在所有的表情符号中查找对应的表情模型对象 - 如果找到返回表情模型,找不到返回nil
    ///
    /// - Parameter string: 目标字符串
    /// - Returns: 表情模型
    func findEmoticon(withString: String) -> SSEmoticon? {
        
        // 1.循环遍历表情包
        for package in packages {
            
            // 2.在数组中过滤string
            let result = package.emoticons.filter { $0.chs == withString }

            // 3.判断结果数组的数量 - 找到1个,马上返回
            if result.count == 1 {
                return result[0]
            }
        }
        
        // 4.没有找到,返回空
        return nil
    }
}
